#ifndef __GXCONTEXT_H
#define __GXCONTEXT_H


#include <stdint.h>
#include <string.h>
#include <string>
#include <map> 
#include "GameTime.h"
#include "link.h"
#include "LuaInterface.h"
#include "TransactionContext.h"



//查了在我们的ubuntu系统上，系统的socket读、写缓存的上限都是163840 byte
//It's 212992 at aliyun
//命令：cat /proc/sys/net/core/rmem_max
// cat /proc/sys/net/core/wmem_max
// 故把这个值定为163840
#define MY_SO_RCVBUF_MAX_LEN 212992

struct GXContext;
#define TRANSACTION_VIRTUAL_INDEX_OFFSET (1024*1024)
#define GXCONTEXT_ID_LEN 16
#define LUA_GX_ID "gGXContextID"
#define GX_LUA_INDICATOR_NUM 4

#define KCP_DELAY_INTERVAL 33



enum{
	UC_currentTransaction = 0,
	UC_connectAsync,
	UC_writeReqAndWait,
	UC_redis,
};

struct KCPPop{
	int pool_idx_;
	char pool_stat_;

	struct IKCPCB *kcp_;
	int udp_sock_;
	struct sockaddr_in remote_;
	uint32_t last_io_time_;

	void reset(){
		kcp_ = NULL;
		udp_sock_ = -1;
		last_io_time_ = 0;
	}
};


struct GXContext{
	enum{
		typeFullFunction = 0,
		typeSimple,
	};
	
	enum{
		typePortalRouter = 0,
		typePortalCustom,
	};

	enum{
		vmhandleUDP = 0,
		vmhandleTCP,
		vmhandleHTTPResponse,
		vmhandleHTTPRequest,
		vmhandleOnCut,
		vmhandleNum
	};
	

	struct VmhandleD{
		int idx_;
		LuaInterface *vm_;
		std::string fname_;

		void reset(){
			idx_ = -1;
			vm_ = NULL;
			fname_ = "";
		}
	};
	
	
#ifdef __USING_WINDOWS_IOCP
	HANDLE iocp_handle_;
#else
	int epoll_fd_;
#endif
	
	s16		type_;		// typeFullFunction or typeSimple
	s16		layer_;		// 层数 
	s16		header_type_;
	s16		stat_;
	bool	enable_encrypt_;
	// -------- 配置信息 --------
	char	tcp_ip_and_port_[128];		// 本上下文的物理地址
	char	udp_ip_and_port_[128];		// 本上下文的物理地址
	char	gx_id_[GXCONTEXT_ID_LEN];
	int		link_pool_size_conf_;
	int		read_buf_len_;
	int		write_fifo_len_;
	int		req_read_buf_len_;
	int		req_write_fifo_len_;
	
	
	int tcp_listening_socket_;
	int udp_listening_socket_;

	timetype cur_frame_gametime_;

	/*
	void *callback_;
	void *callback_http_;
	LinkCut link_cut_callback_;
	*/
	
	int	link_pool_size_;
	Link *link_pool_;

	int trans_pool_size_;
	TransactionContext *trans_pool_;

	int kcp_pop_pool_size_;
	KCPPop *kcp_pop_pool_;

	int prev_link_pool_indicator_;
	int prev_trans_pool_indicator_;
	int prev_kcp_pop_pool_indicator_;
	uint32_t next_trans_serial_no_;
	

	LuaInterface *lua_vm_;
	int lua_stack_indicator_[GX_LUA_INDICATOR_NUM];


	VmhandleD a_vmhandle[vmhandleNum];

	std::map<uint64_t, struct KCPPop*> map_kcp_by_hash_;
	
	
	GXContext():type_(0),layer_(0),header_type_(0),stat_(0),enable_encrypt_(false),link_pool_size_conf_(0),
	link_pool_size_(0),read_buf_len_(0),write_fifo_len_(0),req_read_buf_len_(0),req_write_fifo_len_(0),
	tcp_listening_socket_(-1),udp_listening_socket_(-1),link_pool_(NULL),lua_vm_(NULL),
	prev_link_pool_indicator_(0),prev_trans_pool_indicator_(0),next_trans_serial_no_(0),
	cur_frame_gametime_(0),prev_kcp_pop_pool_indicator_(0),
	#ifdef __USING_WINDOWS_IOCP
	iocp_handle_(0)
	#else
	epoll_fd_(-1)
	#endif
	{
		tcp_ip_and_port_[0] = 0;
		udp_ip_and_port_[0] = 0;
		gx_id_[0] = 0;

		FOR(i, vmhandleNum){
			a_vmhandle[i].reset();
			a_vmhandle[i].idx_ = i;
		}

		FOR(i, GX_LUA_INDICATOR_NUM){
			lua_stack_indicator_[i] = 0;
		}
	}
	
	bool init(int type,const char* ID,int pool_size,int read_buf_len,int write_buf_len,int,int);
	bool initWrap(int type,const char* ID);
	
	void free();
	
	bool resetLinkPool(int poolsize);
	
	/*
	void registerCallback(void* pfun,int ftype=0){	// 注册消息分发回调函数。ftype 为0表示内部消息，1表示客户端消息 
		callback_ = pfun;
		header_type_ = ftype;
	}
	void registerLinkCutCallback(LinkCut pfun){
		link_cut_callback_ = pfun;
	}
	*/
	
	bool start_listening_tcp();
	bool start_listening_udp();
	
	
	void frame_poll(timetype now,int block_time);	// 一帧拉取数据，最多阻塞block_time。帧率控制由外部控制，这个函数无法控制 
	int frame_flush(timetype now);	// 把输出缓冲里的数据flush出去 
	
	
	Link* newLink();
	void releaseLink(Link*);
	Link* getLink(int pool_index);

	TransactionContext* newTrans();
	void releaseTrans(TransactionContext *ll);
	TransactionContext* getTrans(int pool_index);

	KCPPop* newKCPPop();
	void releaseKCPPop(KCPPop *k);
	KCPPop* getKCPPop(int pool_index);

	TransactionContext* createTransactionForKCP(KCPPop *kc, lua_State *L);
	TransactionContext* createTransactionForComingRequest(Link *src, lua_State *L);
	int resumeTransactionAndCheckIfEnd(TransactionContext *tr, int num_param);

	void bindLinkWithGlobalID(char *gid,Link*);
	void unbind(char *gid);
	
	void forceCutLink(Link*);
	
	int connect2_async(const char *ip, int port);

	int regVMHandle(int event, lua_State* l, const char* fname);
	
	
	// GX functions
	int sendToPortal(const char* destID,int datalen,void *data);
	int sendToPortal(int localPoolIndex,const char* destID,int datalen,void *data);		// faster version of above
	int createPortal(int typee,const char* ID);
	int freePortal(int typee,const char* ID);
	int freePortal(int localPoolIndex);
	int findPortal(int typee,const char* ID);
	
	// level-1
	int syncWriteBack(int msgid,int datalen,void *data);
	
	// level-2
	int pushTailJump(u32 local_link_index,const char *ID,kfifo *f);
	
	// level-3
	int packetRouteToNode(const char* destID,int msgid,int datalen,void *data);
	
private:
	bool __helper1(TransactionContext *tr, int num_param, int &r_yield);
	int __helper_udp_recv(const char *buf, int len, struct sockaddr *addr, uint32_t now);
	void __helper_update_all_kcp(uint32_t now);
	uint64_t make_hash_by_sockaddr_value(struct sockaddr *addr);
	int try_deal_one_http(Link *ioable,int &begin);
	
};



// JUST HELP FUNCTIONS
int nc_check_socket_error(int fd);
int nc_setsockopt_server(int fd);
int nc_setsockopt_client(int fd);
int nc_connect(int sock,const char *ip,int port);
int nc_bind(int sock,int port);
int nc_set_no_delay(int sock);
int nc_set_reuse_addr(int sock);
int nc_set_nonblock(int sock);
int nc_get_ip(int sock,char *out_ip,int max_len);
int nc_read(intptr_t fd,char *buf,int buf_len,int &real_read);
int nc_write(intptr_t fd,char *buf,int buf_len,int &real_write);



#endif


